﻿using System.Diagnostics;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

/// <summary>
///     带有参数的可绑定符号的基类，包含FunctionDeclaration，FunctionSignature，MethodSignature，PropertySignature。
/// </summary>
/// <param name="kind">符号类型</param>
/// <param name="declaration">声明节点</param>
/// <param name="containingSymbol">包含此符号的类型符号</param>
/// <param name="containingModule">包含此符号的模块符号</param>
public abstract class BindableSymbolWithParameters(
    SymbolKinds kind,
    IDeclaration? declaration,
    ITypeSymbol? containingSymbol,
    ModuleSymbol? containingModule)
    : BindableSymbol(kind, declaration, containingSymbol, containingModule)
{
    private readonly List<ParameterSymbol> _parameters = [];


    public override bool WithParameter => true;


    /// <summary>
    ///     如果参数列表宽度大于0，返回<see langword="true" />。
    /// </summary>
    public bool HasParameter => _parameters.Count > 0;


    /// <summary>
    ///     当前的参数数量
    /// </summary>
    public int ParametersCount => _parameters.Count;


    /// <summary>
    ///     获取参数列表。
    /// </summary>
    public IReadOnlyList<ParameterSymbol> Parameters => _parameters;


    /// <summary>
    ///     获取指定索引的参数符号。如果最后一个参数带有ParamArray修饰符，即使查找索引超过了
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public ParameterSymbol? GetParameter(int index)
    {
        Debug.Assert(index >= 0);

        if (_parameters.Count == 0)
        {
            return null;
        }

        if (index < _parameters.Count)
        {
            return _parameters[index];
        }

        // 如果超出了参数列表的范围，并且最后一个参数带有ParamArray，返回最后一个参数
        ParameterSymbol last = _parameters[^1];
        return last.IsParamArray ? last : null;
    }


    /// <summary>
    ///     如果可以接收指定数目的参数，返回<see langword="true" />
    /// </summary>
    /// <param name="count">参数个数</param>
    public bool CanAcceptParameters(int count)
    {
        int leastParameters = _parameters.FindIndex(p => !p.IsOptional) + 1;
        return count == ParametersCount || (count >= leastParameters && count <= ParametersCount) ||
               (count > ParametersCount && ParametersCount > 0 && Parameters[^1].IsParamArray);
    }


    /// <summary>
    ///     声明一个参数，如果参数名已存在，将返回<see langword="false" />。
    /// </summary>
    /// <param name="symbol">参数符号</param>
    public bool DeclareLocalVariable(ITypeSymbol symbol)
    {
        if (!NamedMembers.DeclareSymbol(symbol))
        {
            return false;
        }

        if (symbol is { IsParameter: true })
        {
            _parameters.Add((ParameterSymbol)symbol);
        }

        return true;
    }
}